package com.example.demo.service.impl;

import com.example.demo.entity.Banner;
import com.example.demo.entity.ResourceFile;
import com.example.demo.mapper.BannerMapper;
import com.example.demo.service.BannerService;
import com.example.demo.service.ResourceFileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 轮播图服务层实现类
 *
 * @author 叮当猫的百宝箱
 * @since 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BannerServiceImpl implements BannerService {

    private final BannerMapper bannerMapper;

    private final ResourceFileService resourceService;

    /**
     * 根据轮播图ID获取轮播图信息
     *
     * @param id 轮播图ID
     * @return 轮播图信息，不存在返回null
     */
    @Override
    public Banner getBannerById(Long id) {
        return bannerMapper.findById(id);
    }

    /**
     * 添加一张新的轮播图
     *
     * @param banner 带添加的轮播图信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(Banner banner) {
        // 如果没有设置为长期有效，则生效日期和失效日期不能为空
        if (!isBannerPermanent(banner) || !isBannerValidPeriodSet(banner)) {
            throw new RuntimeException("未设置轮播图有效期!");
        }

        ResourceFile resource = resourceService.getResourceById(banner.getResourceId());
        if (resource == null || resource.getDeleted() == 1 || resource.getUsed() == 1) {
            throw new RuntimeException("Resource NotFound");
        }
        banner.setPath(resource.getPath());
        bannerMapper.insert(banner);
        // 将这个资源标记为使用状态
        resourceService.markAsUsedById(banner.getResourceId());
    }

    /**
     * 根据ID更新轮播图信息
     *
     * @param id     轮播图ID
     * @param banner 待更新的轮播图信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(Long id, Banner banner) {
        Banner originalBanner = getBannerById(id);
        banner.setPath(null);
        if (originalBanner != null) {
            if (isUpdateResourceId(originalBanner, banner)) {
                // 说明修改了新的图片,检查一下新资源是否存
                ResourceFile resource = resourceService.getResourceById(banner.getResourceId());
                if (resource == null || resource.getDeleted() == 1) {
                    throw new RuntimeException("Resource NotFound");
                }
                banner.setPath(resource.getPath());
                // 将新的图片设置为被使用状态
                resourceService.markAsUsedById(banner.getResourceId());
                // 将原始的资源ID标记为未使用，等待系统回收
                resourceService.markAsNotUsedById(originalBanner.getResourceId());
            }

            bannerMapper.updateSelectiveById(id, banner);
        }
    }

    /**
     * 根据轮播图ID删除轮播图
     *
     * @param id 轮播图ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        Banner banner = bannerMapper.findById(id);
        if (banner != null) {
            Long resourceId = banner.getResourceId();
            resourceService.deleteById(resourceId);
            bannerMapper.deleteById(id);
        }
    }

    /**
     * 获取全部轮播图列表
     *
     * @return 轮播图列表
     */
    @Override
    public List<Banner> getAllBanner() {
        return bannerMapper.findAll();
    }

    /**
     * 轮播图是否长期有效
     *
     * @param banner 轮播图详情
     * @return 长期有效返回true, 否则返回false
     */
    private boolean isBannerPermanent(Banner banner) {
        return banner.getPermanent() != null && banner.getPermanent() == 1;
    }

    /**
     * 轮播图是否设置了生效时间和失效时间
     *
     * @param banner 轮播图详情
     * @return 正确设置生效时间段返回true, 否则返回false
     */
    private boolean isBannerValidPeriodSet(Banner banner) {
        return banner.getValidFrom() == null || banner.getValidTo() == null;
    }

    /**
     * 是否更新了论不图的图片
     *
     * @param originalBanner 原始的轮播图信息
     * @param newBanner      新的轮播图信息
     * @return 如果资源id发生了变化则返回t rue,否则返回 false
     */
    private boolean isUpdateResourceId(Banner originalBanner, Banner newBanner) {
        return newBanner.getResourceId() != null
                && !originalBanner.getId().equals(newBanner.getResourceId());
    }
}
